﻿using System;
using System.Linq;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using LinqKit;
using Syncfusion.Drawing;
using Syncfusion.Windows.Forms.Grid.Grouping;
using Syncfusion.DocIO;
using Syncfusion.DocIO.DLS;
using Syncfusion.GridExcelConverter;
using Syncfusion.GroupingGridExcelConverter;
using PMngr.Data;

namespace PMngr.Main
{
    public partial class ProfileUpdate : BaseControl
    {
        private IRepositoryFactory repositoryFactory;

        public ProfileUpdate()
        {
            InitializeComponent();
            InitializeGridGrouping();

            dtFrom.Value = DateTime.Today.AddDays(-7);
            dtTo.Value = DateTime.Today;
        }

        public ProfileUpdate(IRepositoryFactory repositoryFactory) : this()
        {
            this.repositoryFactory = repositoryFactory;            
        }

        public override void InitializeControls()
        {
            chkPrinting.Checked = true;
            chkPrinted.Checked = false;
            chkApproved.Checked = false;
            chkWhole.Checked = false;
            bindingSource.DataSource = null;
        }

        private void InitializeGridGrouping()
        {
            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(ProfileModel)))
            {
                var gcd = new GridColumnDescriptor(pd.Name, pd.Name, ProfileModel.Dict[pd.Name]);
                gridList.TableDescriptor.Columns.Add(gcd);
            }
            gridList.TableDescriptor.Name = @"调动人员";
            gridList.TableDescriptor.FrozenColumn = ProfileModel.GetPropertyName(u => u.Name);
            // hide the trivial items
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.UserId));
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.MarriedDate));
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.Family));
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.Checked));
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.PrintDate));
            gridList.TableDescriptor.VisibleColumns.Remove(ProfileModel.GetPropertyName(p => p.WholeTransferId));
            
            gridList.InitializeGridGrouping();
            // caption
            gridList.TopLevelGroupOptions.ShowCaption = true;
            gridList.TopLevelGroupOptions.CaptionText = Utilities.CategoryCaption;
            gridList.ChildGroupOptions.CaptionText = Utilities.CategoryCaption;
            // group drop
            gridList.ShowGroupDropArea = true;
            gridList.GridGroupDropArea.DragColumnHeaderText = Utilities.Grouping;

            gridList.DataSource = bindingSource;
            gridList.TableControlMouseDown += GlOptionsTableControlMouseDown;
            gridList.QueryCellStyleInfo += GridGroupingControl1QueryCellStyleInfo;
            gridList.TableControlCellDoubleClick += TableControlCellDoubleClick;
        }

        private void BtnSearchClick(object sender, EventArgs e)
        {
            var name = txtName.Text;
            var fromDate = dtFrom.Value.FromDate();
            var toDate = dtTo.Value.ToDate();

            var predicate = PredicateBuilder.True<Profile>();
            predicate = chkApproved.Checked
                            ? predicate.And(p => p.ApprovalDate != null)
                            : predicate.And(p => p.ApprovalDate == null);

            var printPredicate = PredicateBuilder.False<Profile>();
            if (chkPrinted.Checked)
                printPredicate = printPredicate.Or(p => p.PrintDate != null);
            if (chkPrinting.Checked)
                printPredicate = printPredicate.Or(p => p.PrintDate == null);
            predicate = predicate.And(printPredicate.Expand());

            if (!chkWhole.Checked)
                predicate = predicate.And(p => p.WholeTransfer == null);            

            if (!String.IsNullOrWhiteSpace(name))
                predicate = predicate.And(p => p.Name.Contains(name));

            predicate = predicate.And(p => p.RecordDate >= fromDate && p.RecordDate <= toDate);

            using (var repository = repositoryFactory.CreateRepository())
            {
                var dataSource = repository.Find(predicate.Expand()).Select(p => new ProfileModel
                {
                    UserId = p.UserId,
                    Name = p.Name,
                    Nationality = p.Nationality,
                    BirthDate = p.BirthDate,
                    Gender = p.Gender,
                    Family = p.Family,
                    SchoolRecord = p.SchoolRecord.Name,
                    SchoolLevel = p.SchoolLevel.Name,
                    PolicyFace = p.PolicyFace.Name,
                    MarriedDate = p.MarriedDate,
                    College = p.College,
                    Major = p.Major,
                    InUnit = p.OriginalIn,      // 原调入单位
                    OutUnit = p.OriginalOut,    // 原调出单位
                    ProfPos = p.ProfPos,
                    ProfTitle = p.ProfTitle,
                    PersonalIdentity = p.PersonalIdentity.Name,
                    TechGrade = p.TechGrade.Name,
                    WorkKind = p.WorkKind,
                    WorkStart = p.WorkStart,
                    TransferReason = p.TransferReason.Name,
                    Remark1 = p.Remark1,
                    SalaryGrade = p.SalaryGrade,
                    RecordDate = p.RecordDate,
                    ApprovalDate = p.ApprovalDate,
                    WholeTransferId = p.WholeTransfer.Id,
                    PrintDate = p.PrintDate
                });

                var result = dataSource.ToList();
                bindingSource.DataSource = result;
            }
            //
            if (chkWhole.Checked)
                gridList.Appearance.AlternateRecordFieldCell.Interior = gridList.Appearance.RecordFieldCell.Interior;
            else
                gridList.Appearance.AlternateRecordFieldCell.Interior = new BrushInfo(Color.Gainsboro);
        }

        private void TableControlCellDoubleClick(object sender, GridTableControlCellClickEventArgs e)
        {
            var style = e.TableControl.GetTableViewStyleInfo(e.Inner.RowIndex, e.Inner.ColIndex);
            if (style.TableCellIdentity.TableCellType == GridTableCellType.RecordFieldCell ||
                style.TableCellIdentity.TableCellType == GridTableCellType.AlternateRecordFieldCell ||
                style.TableCellIdentity.TableCellType == GridTableCellType.RecordRowHeaderCell ||
                style.TableCellIdentity.TableCellType == GridTableCellType.AlternateRecordRowHeaderCell)
            {
                UpdateToolStripMenuItemClick(sender, e);
            }
        }

        private void UpdateToolStripMenuItemClick(object sender, EventArgs e)
        {
            var selecteds = gridList.Table.SelectedRecords;
            if (selecteds != null && selecteds.Count > 0)
            {
                using (var repository = repositoryFactory.CreateRepository())
                {
                    var selected = selecteds[0].Record;
                    var profileId = (int)selected.GetValue(ProfileModel.GetPropertyName(p => p.UserId));

                    var popUp = new UpdateProfile(repositoryFactory, profileId);
                    var result = popUp.ShowDialog(this);
                    if (DialogResult.OK == result)
                    {
                        LogTrace(String.Format(Utilities.SuccessUpdated, popUp.Name));

                        BtnSearchClick(sender, e);
                    }
                }
            }
        }

        private void ExcelToolStripMenuItemClick(object sender, EventArgs e)
        {
            var saveFileDialog = new SaveFileDialog
                                     {
                                         Filter = @"Files(*.xls)|*.xls",
                                         FileName = String.Format("{0}.xls", DateTime.Now.ToString("yyyyMMddhhmmss")),
                                         AddExtension = true,
                                         DefaultExt = ".xls"
                                     };

            if (saveFileDialog.ShowDialog() == DialogResult.OK && saveFileDialog.CheckPathExists)
            {
                gridList.ExportToExcel(saveFileDialog.FileName);

                if (MessageFactory.MessageBoxShow(Utilities.OpenExcelConfirmed) == DialogResult.Yes)
                {
                    var proc = new System.Diagnostics.Process {StartInfo = {FileName = saveFileDialog.FileName}};
                    proc.Start();
                }
            }
        }

        void GlOptionsTableControlMouseDown(object sender, GridTableControlMouseEventArgs e)
        {
            if (e.Inner.Button == MouseButtons.Right)
            {
                int row, col;
                var pt = new Point(e.Inner.X, e.Inner.Y);

                if (e.TableControl.PointToRowCol(pt, out row, out col))
                    e.TableControl.CurrentCell.AdjustRowColIfCoveredCell(ref row, ref col);

                var style = gridList.TableControl.Model[row, col];
                if (style.TableCellIdentity.TableCellType == GridTableCellType.RecordFieldCell || style.TableCellIdentity.TableCellType == GridTableCellType.AlternateRecordFieldCell)
                {
                    // get the row information
                    var selectRecord = e.TableControl.Table.Records[row - 3];
                    if (selectRecord != null && selectRecord.IsRecord())
                    {
                        var approvalDate = selectRecord.GetValue(ProfileModel.GetPropertyName(p => p.ApprovalDate));
                        var wholeTransfer = selectRecord.GetValue(ProfileModel.GetPropertyName(p => p.WholeTransferId));
                        if (approvalDate == null)
                        {
                            contextMenu.Items["UpdateToolStripMenuItem"].Visible = true;
                            contextMenu.Items["DeleteToolStripMenuItem"].Visible = true;
                            contextMenu.Items["ApprovalToolStripMenuItem"].Visible = wholeTransfer == null;
                        }
                        else
                        {
                            contextMenu.Items["UpdateToolStripMenuItem"].Visible = true;
                            contextMenu.Items["DeleteToolStripMenuItem"].Visible = true;
                            contextMenu.Items["ApprovalToolStripMenuItem"].Visible = false;
                        }
                    }
                }
                else
                {
                    contextMenu.Items["UpdateToolStripMenuItem"].Visible = false;
                    contextMenu.Items["DeleteToolStripMenuItem"].Visible = false;
                    contextMenu.Items["ApprovalToolStripMenuItem"].Visible = false;
                }
            }
        }

        private UnitInfo GetUnitInstance(int userId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var profile = repository.Find<Profile>(userId);
                var inUnit = new UnitInfo { UnitType = profile.OriginalInUnitType, UnitKind = profile.OriginalInUnitKind };
                var outUnit = new UnitInfo { UnitType = profile.OriginalOutUnitType, UnitKind = profile.OriginalOutUnitKind };
                return new UnitInfo { InUnit = inUnit, OutUnit = outUnit };
            }
        }

        private static string GetUnitKind(string unitKind)
        {
            string result = unitKind;
            if (unitKind == "参公事业" || unitKind == "全额事业" || unitKind == "差额事业" || unitKind == "自收自支事业")
                result = String.Format("{0}单位", unitKind);

            return result;
        }
        // 调动类型     false -> 调入, true -> 调出
        private bool GetTransferKind(int userId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var profile = repository.Find<Profile>(userId);
                return profile.TransferKind;
            }
        }
        // 出生日期格式为 XXXX年XX月
        private static string GetNullableDate(DateTime? dateTime)
        {
            return dateTime.HasValue ? dateTime.Value.ToString("yyyy年M月") : String.Empty;
        }
        // 承办人审查情况日期格式为 XXXX年XX月XX日
        private static string GetRecordDate(DateTime dateTime)
        {
            return dateTime.ToString("yyyy年M月d日");
        }

        private void ApprovalToolStripMenuItemClick(object sender, EventArgs e)
        {
            var selecteds = gridList.Table.SelectedRecords;
            if (selecteds != null && selecteds.Count > 0)
            {
                var selected = selecteds[0].Record;
                var saveFileDialog = new SaveFileDialog
                                         {
                                             Filter = @"Files(*.doc)|*.doc",
                                             FileName = String.Format("{0}.doc", DateTime.Now.ToString("yyyyMMddhhmmss")),
                                             AddExtension = true,
                                             DefaultExt = ".doc"
                                         };

                if (saveFileDialog.ShowDialog() == DialogResult.OK && saveFileDialog.CheckPathExists)
                {
                    var profile = selected.GetData() as ProfileModel;
                    if (profile == null) return;
                    // Create a new document.
                    var document = new WordDocument();
                    IEnumerable data = null;
                    var userId = profile.UserId;
                    var identity = profile.PersonalIdentity;
                    if (identity != null)
                    {
                        // 如果调入单位调出单位均为市直的单位，则：“调出单位性质”& 调 &“调入单位性质”；
                        // 如果调出单位不是市直的单位，则：“调出单位区域”&“调出单位性质”& 调 &“调入单位区域”&“调入单位性质”。
                        // 如果调出单位为“人力资源市场”，则：“调出单位区域”&“调出单位性质” & 挂档人员调 &“调入单位区域”&“调入单位性质”。                        
                        var unit = GetUnitInstance(userId);
                        var inUnitKind = GetUnitKind(unit.InUnit.UnitKind);
                        var outUnitKind = GetUnitKind(unit.OutUnit.UnitKind);
                        string template;
                        // 承办人审查情况及意见，如果是调出审批单则输出“调出”即可！
                        //  要求：“调出”两个字居中
                        var transferKind = GetTransferKind(userId);
                        string approval;
                        if (transferKind)
                        {
                            approval = "调出";
                        }
                        else
                        {
                            if (unit.InUnit.UnitType == "市直" && unit.OutUnit.UnitType == "市直")
                            {
                                if (unit.OutUnit.UnitKind == "人力资源市场")
                                    approval = String.Format("{0}挂档人员调{1}。", outUnitKind, inUnitKind);
                                else
                                    approval = String.Format("{0}调{1}。", outUnitKind, inUnitKind);

                            }
                            else if (unit.OutUnit.UnitKind == "人力资源市场")
                                approval = String.Format("{0}{1}挂档人员调{2}{3}。", unit.OutUnit.UnitType, outUnitKind, unit.InUnit.UnitType, inUnitKind);
                            else
                                approval = String.Format("{0}{1}调{2}{3}。", unit.OutUnit.UnitType, outUnitKind, unit.InUnit.UnitType, inUnitKind);
                        }

                        if (identity == "干部")
                        {
                            template = Application.StartupPath + @".\docs\template1.doc";
                            // Loading Template.
                            document.Open(template, FormatType.Doc);
                            //Executes mail merge for the selected record or row
                            data = new[]{ 
                            new {
                                    profile.Name,
                                    profile.Gender,
                                    BirthDate = GetNullableDate(profile.BirthDate),
                                    RecordDate = GetRecordDate(profile.RecordDate),
                                    profile.SchoolRecord,
                                    profile.ProfPos,
                                    profile.ProfTitle,
                                    profile.Family,
                                    profile.OutUnit,
                                    profile.InUnit,
                                    profile.TransferReason,
                                    Approval = approval
                            }};
                        }
                        else if (identity == "聘用制干部")
                        {
                            template = Application.StartupPath + @".\docs\template2.doc";
                            document.Open(template, FormatType.Doc);
                            data = new[]{ 
                            new {
                                    profile.Name,
                                    profile.Gender,
                                    BirthDate = GetNullableDate(profile.BirthDate),
                                    RecordDate = GetRecordDate(profile.RecordDate),
                                    profile.SchoolRecord,
                                    profile.ProfPos,
                                    profile.ProfTitle,
                                    profile.Family,
                                    profile.OutUnit,
                                    profile.InUnit,
                                    profile.TransferReason,
                                    Approval = approval
                            }};
                        }
                        else    //工勤人员
                        {
                            template = Application.StartupPath + @".\docs\template3.doc";
                            document.Open(template, FormatType.Doc);
                            data = new[]{ 
                            new {
                                    profile.Name,
                                    profile.Gender,
                                    BirthDate = GetNullableDate(profile.BirthDate),
                                    RecordDate = GetRecordDate(profile.RecordDate),
                                    profile.SchoolRecord,
                                    profile.WorkKind,
                                    profile.TechGrade,
                                    profile.Family,
                                    profile.OutUnit,
                                    profile.InUnit,
                                    profile.TransferReason,
                                    Approval = approval
                            }};
                        }

                        if (approval == "调出")
                        {
                            // Using Merge events to do conditional formatting during runtime.
                            document.MailMerge.MergeField += new MergeFieldEventHandler(ApproveMergeField);
                        }
                    }

                    document.MailMerge.Execute(data);
                    // saving the document to disk.
                    document.Save(saveFileDialog.FileName);
                    // 对已打印的记录做个标记
                    SavePrintFlag(userId);
                    LogWriter(String.Format(Utilities.PrintApprovalDoc, profile.Name));
                    //Message box confirmation to view the created document.
                    if (MessageFactory.MessageBoxShow(Utilities.OpenWordConfirmed) == DialogResult.Yes)
                    {
                        var proc = new System.Diagnostics.Process {StartInfo = {FileName = saveFileDialog.FileName}};
                        proc.Start();
                    }

                    BtnSearchClick(sender, e);
                }
            }
        }

        private static void ApproveMergeField(object sender, MergeFieldEventArgs args)
        {
            // Conditionally format data during Merge.
            if (args.FieldName == "Approval")
            {
                args.CurrentMergeField.OwnerParagraph.ParagraphFormat.HorizontalAlignment = Syncfusion.DocIO.DLS.HorizontalAlignment.Center;
            }
        }

        private void SavePrintFlag(int id)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var profile = repository.Find<Profile>(id);
                profile.PrintDate = DateTime.Now;
                repository.CommitChanges();
            }
        }

        private void DeleteToolStripMenuItemClick(object sender, EventArgs e)
        {
            try
            {
                var selecteds = gridList.Table.SelectedRecords;
                if (selecteds != null && selecteds.Count > 0)
                {
                    var selected = selecteds[0].Record;
                    var model = selected.GetData() as ProfileModel;
                    if (model == null) return;

                    var profileId = model.UserId;
                    // 判断是否已审批结束，不能再修改，删除
                    var approvalDate = model.ApprovalDate;
                    DialogResult dialogResult;
                    if (approvalDate != null)
                        dialogResult = MessageBoxShow(Utilities.ComfirmApproved);
                    else
                        dialogResult = MessageBoxShow(Utilities.DeleteConfirmed);

                    if (dialogResult == DialogResult.Yes)
                    {
                        using (var repository = repositoryFactory.CreateRepository())
                        {
                            repository.Delete<Profile>(u => u.UserId == profileId);
                            repository.CommitChanges();
                        }
                        LogWriter(String.Format(Utilities.ProfileDeleted, model.Name));
                        BtnSearchClick(sender, e);
                    }
                }
            }
            catch (Exception ex)
            {
                LogTrace(String.Format(Utilities.DeleteInnerError, ex.Message), MessageType.Error);
            }
        }

        private static readonly Color[] colors = new Color[] 
            {  
                Color.FromArgb(41,158,214),
                Color.FromArgb(206,215,41),
                Color.FromArgb(250,236,35),
                Color.FromArgb(155,166,184),
                Color.FromArgb(255,146,140),
                Color.FromArgb(180,192,98),
                Color.FromArgb(247,125,16)         
            };

        private static void GridGroupingControl1QueryCellStyleInfo(object sender, GridTableCellStyleInfoEventArgs e)
        {
            // format the datetime field
            if (e.Style.CellValueType == typeof(DateTime) || e.Style.CellValueType == typeof(DateTime?))
            {
                if (e.TableCellIdentity.Column.Name != ProfileModel.GetPropertyName(p => p.RecordDate) && e.TableCellIdentity.Column.Name != ProfileModel.GetPropertyName(p => p.ApprovalDate))
                    e.Style.Format = "d";
            }

            if (e.TableCellIdentity.TableCellType == GridTableCellType.RecordFieldCell || e.TableCellIdentity.TableCellType == GridTableCellType.AlternateRecordFieldCell)
            {
                var row = e.TableCellIdentity.DisplayElement.GetData() as ProfileModel;
                if (row == null) return;

                if (!row.WholeTransferId.HasValue) return;

                var wholeId = row.WholeTransferId.Value;

                var index = wholeId % 7;
                var color = colors[index];
                e.Style.BackColor = color;
            }
            e.Handled = true;
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Enter)
            {
                BtnSearchClick(this, EventArgs.Empty);
                return true;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }    
    }

    class UnitInfo
    {
        public string UnitType { get; set; }
        public string UnitKind { get; set; }

        public UnitInfo InUnit { get; set; }
        public UnitInfo OutUnit { get; set; }
    }
}
